/**
 * Created by wm123 on 2017/7/13.
 */
const { Board, utils } = require('board-game');
const extend = require('extend');
const { game } = require('./config');
const maps = require('./maps');

const hint = (value, ship) => value === 0 || value === 7 || value === 9 || value === 8 && ship;
const brick = {
    fields: [1, 2, 3, 4, 5, 10, 11, 12, 13],
    '1': [1, 1, 1, 1].join(''),
    '2': [1, 1, 0, 0].join(''),
    '3': [0, 1, 0, 1].join(''),
    '4': [0, 0, 1, 1].join(''),
    '5': [1, 0, 1, 0].join(''),
    '10': [1, 0, 0, 0].join(''),
    '11': [0, 1, 0, 0].join(''),
    '12': [0, 0, 0, 1].join(''),
    '13': [0, 0, 1, 0].join(''),
    find(field) {
        field = Array.isArray(field) ? field.join('') : field;
        return ~~this.fields.find(key => this[key] === field);
    },
    hint(field,direction) {
        field = Array.isArray(field) ? field : field.split('');
        switch (direction) {
            case game.direction.top: return ~~field[0] !== 0 || ~~field[1] !== 0;
            case game.direction.right: return ~~field[1] !== 0 || ~~field[3] !== 0;
            case game.direction.bottom: return ~~field[2] !== 0 || ~~field[3] !== 0;
            case game.direction.left: return ~~field[0] !== 0 || ~~field[2] !== 0;
        }
        return false;
    },
    remove(field, direction) {
        field = Array.isArray(field) ? field : field.split('');
        switch (direction) {
            case game.direction.top: field[0] = 0; field[1] = 0; break;
            case game.direction.right: field[1] = 0; field[3] = 0; break;
            case game.direction.bottom: field[2] = 0; field[3] = 0; break;
            case game.direction.left: field[0] = 0; field[2] = 0; break;
        }
        return field;
    }
};
const canCross = (value, direction) => {
    if (value === 0 || value === 7 || value === 8 || value === 9 || value === 98) return true;
    if (value === 1 || value === 6 || value === 99) return false;
    switch (direction) {
        case game.direction.top: return value === 4 || value === 12 || value === 13;
        case game.direction.right: return value === 5 || value === 10 || value === 13;
        case game.direction.bottom: return value === 2 || value === 10 || value === 11;
        case game.direction.left: return value === 3 || value === 11 || value === 12;
    }
    return false;
};
const getLeft = direction => (direction + 3) % 4;
const getRight = direction => (direction + 1) % 4;
const getReverse = direction => (direction + 2) % 4;
const shot = (board, bullet, map, leftX, leftY, rightX, rightY, half, direction, strong) => {
    let left = map[leftY][leftX];
    let right = map[rightY][rightX];
    let crossLeft = canCross(left, getRight(direction));
    let crossRight = canCross(right, getLeft(direction));
    if (strong >= 4) {
        if (left === game.tile.grass) map[leftY][leftX] = 0;
        if (right === game.tile.grass) map[rightY][rightX] = 0;
    }
    if (crossLeft && crossRight) {
        return false;
    } else {
        if (left === 99 || right === 99) {
            if (strong >= 3 || (left !== game.tile.steel && right !== game.tile.steel)) {
                game.home.forEach(({ y, x }) => map[y][x] = 98);
                if (!bullet.tank.isEnemy) {
                    board.killer = bullet;
                }
            }
            return true;
        }
        if (strong >= 3) {
            if (!crossLeft) map[leftY][leftX] = 0;
            if (!crossRight) map[rightY][rightX] = 0;
        } else if (strong >= 2) {
            if (left !== game.tile.steel && right !== game.tile.steel) {
                if (!crossLeft) map[leftY][leftX] = 0;
                if (!crossRight) map[rightY][rightX] = 0;
            }
        } else {
            if (left !== game.tile.steel && right !== game.tile.steel) {
                if (!crossLeft && brick.hint(brick[left], getReverse(direction)) || !crossRight && brick.hint(brick[right], getReverse(direction))) {
                    if (!crossLeft) map[leftY][leftX] = brick.find(brick.remove(brick[left], getReverse(direction)));
                    if (!crossRight) map[rightY][rightX] = brick.find(brick.remove(brick[right], getReverse(direction)));
                } else if (half) {
                    if (!crossLeft) map[leftY][leftX] = 0;
                    if (!crossRight) map[rightY][rightX] = 0;
                } else {
                    return false;
                }
            }
        }
        return true;
    }
};

class TankBoard extends Board {
    constructor(game) {
        super(game);
        this.stage = 0;
        this.count = 0;
        this.map = [];
        this.end = false;
        this.killer = false;
    }
    get index() {
        return this.count > 0 ? this.count - 1 : 0;
    }
    next() {
        this.stage++;
        if (!this.loadMap()) {
            this.stage--;
            this.end = true;
            return false;
        } else {
            return true;
        }
    }
    loadMap() {
        if (this.stage > maps.length) return false;
        let map = maps[this.stage - 1];
        this.enemies = map.enemies;
        this.map = map.tiles.map(line => line.slice());
        if (map.auto) {
            for (let y = 0; y < 50; y++) {
                for (let x = 0; x < 50; x++) {
                    if (x < 12 && y < 12) {
                        this.map[y][x] = this.map[y][x + 26];
                    } else if (x >= 38 && y < 12) {
                        this.map[y][x] = this.map[y][x - 24];
                    } else if (x < 12 && y >= 12 && y < 38) {
                        this.map[y][x] = this.map[x][49 - y];
                    } else if (x >= 38 && y >= 12 && y < 38) {
                        this.map[y][x] = this.map[49 - x][y];
                    } else if (y >= 38 || (y > 25 && x >= 12 && x < 38)) {
                        this.map[y][x] = this.map[49 - y][49 - x];
                    }
                }
            }
        }
        for (let { x, y } of game.enemies[this.index]) {
            this.map[y - 1][x - 1] = 0;
            this.map[y][x - 1] = 0;
            this.map[y - 1][x] = 0;
            this.map[y][x] = 0;
        }
        for (let { x, y } of game.locations[this.index]) {
            this.map[y - 1][x - 1] = 0;
            this.map[y][x - 1] = 0;
            this.map[y - 1][x] = 0;
            this.map[y][x] = 0;
        }
        game.home.forEach(({ y, x }) => this.map[y][x] = 99);
        this.setWrapper(this.settings.wrapper ? 1 : 0, []);
        return true;
    }
    isIce(xs, ys) {
        for (let x of xs) {
            for (let y of ys) {
                if (this.map[y][x] === game.tile.ice) {
                    return true;
                }
            }
        }
        return false;
    }
    setWrapper(value, tanks) {
        game.wrapper.filter(location => !tanks.filter(tank => tank.life > 0 && (tank === 'death' || tank === 'stop' || tank === 'moving' || tank === 'original')).some(tank => tank.hint(location))).forEach(({ y, x }) => this.map[y][x] = value);
    }
    hint({ left, right, top, bottom }, { x, y }, direction, ship = false) {
        switch (direction) {
            case game.direction.top: return y > top && hint(this.map[y - 1][x - 1], ship) && hint(this.map[y - 1][x], ship);
            case game.direction.right: return x < right && hint(this.map[y - 1][x], ship) && hint(this.map[y][x], ship);
            case game.direction.bottom: return y < bottom && hint(this.map[y][x - 1], ship) && hint(this.map[y][x], ship);
            case game.direction.left: return x > left && hint(this.map[y - 1][x - 1], ship) && hint(this.map[y][x - 1], ship);
            default: return hint(this.map[y][x], ship);
        }
    }
    getTile({ left, right, top, bottom }, { x, y }, direction) {
        switch (direction) {
            case game.direction.top:
                if (y <= top * 100) {
                    return false;
                } else {
                    x = Math.round(x / 100);
                    y = Math.ceil(y / 100);
                    return { left: this.map[y - 1][x - 1], right: this.map[y - 1][x] };
                }
            case game.direction.right:
                if (x >= right * 100) {
                    return false;
                } else {
                    x = Math.floor(x / 100);
                    y = Math.round(y / 100);
                    return { left: this.map[y - 1][x], right: this.map[y][x] };
                }
            case game.direction.bottom:
                if (y >= bottom * 100) {
                    return false;
                } else {
                    x = Math.round(x / 100);
                    y = Math.floor(y / 100);
                    return { left: this.map[y][x], right: this.map[y][x - 1] };
                }
            case game.direction.left:
                if (x <= left * 100) {
                    return false;
                } else {
                    x = Math.ceil(x / 100);
                    y = Math.round(y / 100);
                    return { left: this.map[y][x - 1], right: this.map[y - 1][x - 1] };
                }
            default: return false;
        }
    }
    shot(bullet, { left, right, top, bottom }, { x, y }, direction, strong) {
        switch (direction) {
            case game.direction.top:
                if (y <= top * 100) {
                    return true;
                } else {
                    let half = y % 100 < 50;
                    x = Math.round(x / 100);
                    y = Math.ceil(y / 100);
                    return shot(this, bullet, this.map, x - 1, y - 1, x, y - 1, half, direction, strong);
                }
            case game.direction.right:
                if (x >= right * 100) {
                    return true;
                } else {
                    let half = x % 100 >= 50;
                    x = Math.floor(x / 100);
                    y = Math.round(y / 100);
                    return shot(this, bullet, this.map, x, y - 1, x, y, half, direction, strong);
                }
            case game.direction.bottom:
                if (y >= bottom * 100) {
                    return true;
                } else {
                    let half = y % 100 >= 50;
                    x = Math.round(x / 100);
                    y = Math.floor(y / 100);
                    return shot(this, bullet, this.map, x, y, x - 1, y, half, direction, strong);
                }
            case game.direction.left:
                if (x <= left * 100) {
                    return true;
                } else {
                    let half = x % 100 < 50;
                    x = Math.ceil(x / 100);
                    y = Math.round(y / 100);
                    return shot(this, bullet, this.map, x - 1, y, x - 1, y - 1, half, direction, strong);
                }
            default: return false;
        }
    }
    get data() {
        return extend(true, super.data, {
            stage: this.stage,
            map: utils.asObject(this.map, true)
        });
    }
    isOver() {
        return this.end || this.stage > maps.length || this.map && this.map[24][24] === 98 || this.killer;
    }
    isWin() {
        return this.end;
    }
}

module.exports = TankBoard;
